#include <Positioning.h>
#include <ipcp/ipcp.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define LOCAL_SERVER_IP "198.18.34.15"
#define LOCAL_SERVER_PORT 8766

#define PEER_CLIENT_IP "198.18.34.15"
#define PEER_CLIENT_PORT ASN1V_positioningPort

#define SERVICE_ID ASN1V_positioningServiceID

#define MAX_PAYLOAD (65507 - 16)

void received_cb(ipcp_packet_t* packet, ipcp_peer_t peer);
void error_cb(ipcp_packet_t* ipcp_packet, ipcp_stack_err_t error);
void init_service_side(ipcp_transport_conf_t* config);
void init_client_side(ipcp_transport_conf_t* config);

ipcp_packet_t* upper_packet = NULL;

static ipcp_peer_t udp_peer = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = PEER_CLIENT_IP,
    .peer_port = PEER_CLIENT_PORT,
};

ipcp_callbacks_t callbacks = {
    .ipcp_received_cb = received_cb,
    .error_cb = error_cb,
};

void received_cb(ipcp_packet_t* packet, ipcp_peer_t peer) {
    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length + 8;

    upper_packet = (ipcp_packet_t*)calloc(1, len);
    memcpy(upper_packet, packet, len);

    printf("%s, received ipcp header : sid: %hu, sender_handler_id : %#x \n", __func__,
           upper_packet->header.service_id, upper_packet->header.senderHandleId);
    printf("%s, payload %s \n", __func__, upper_packet->payload);
}

void error_cb(ipcp_packet_t* ipcp_packet, ipcp_stack_err_t error) {
    printf("%s, test demo... %d", __func__, error);
}

void init_client_side(ipcp_transport_conf_t* config) {
    config->service_id = SERVICE_ID;
    strcpy(config->host_ip, LOCAL_SERVER_IP);
    config->host_port = LOCAL_SERVER_PORT;
    config->sk_type = IPCP_TRANSPORT_UDP;
    config->vlan = 5;
    config->priority = 5;
}

int main(int argc, char** argv) {
    ipcp_transport_conf_t config;
    ipcp_stack_err_t error_code;
    ipcp_packet_t* packet;

    init_client_side(&config);

    printf("#1 start IPCP Client STACK \n");
    set_log_tag("GNSS_XMA_Client");
    error_code = ipcp_setup(config, &callbacks);

    uint16_t service_id = SERVICE_ID;
    uint16_t oper_id = ASN1V_poiInfoPushOpID;
    uint8_t oper_type = IPCP_OPERATION_NOTIFICATION;
    uint8_t payload_type = IPCP_DATA_NORMAL;
    const OSOCTET* msgptr = nullptr;
    int len;

    printf("#2 Send UDP Request to Server\n");

    ASN1PEREncodeBuffer encodeBuffer(false);
    ASN1T_OpPOIInfoPush_Notification data;
    data.poiname = (const OSUTF8CHAR*)"星海广场";
    data.longitude = 121.583f * 3600000;
    data.latitude = 38.880f* 3600000;
    data.m.postAddressPresent = 1;
    data.postAddress.m.streetPresent = 1;
    data.postAddress.street = (const OSUTF8CHAR*)"street";
    data.postAddress.m.houseNumberPresent = 1;
    data.postAddress.houseNumber = (const OSUTF8CHAR*)"houseNumber";
    data.postAddress.m.cityPresent = 1;
    data.postAddress.city = (const OSUTF8CHAR*)"city";
    data.postAddress.m.regionPresent = 1;
    data.postAddress.region = (const OSUTF8CHAR*)"region";
    data.postAddress.m.postcodePresent = 1;
    data.postAddress.postcode = (const OSUTF8CHAR*)"postcode";
    data.postAddress.m.countryPresent = 1;
    data.postAddress.country = (const OSUTF8CHAR*)"country";

    ASN1C_OpPOIInfoPush_Notification OpPOIInfoPush_NotificationPDU(encodeBuffer, data);

    if ((OpPOIInfoPush_NotificationPDU.Encode()) == 0) {
        msgptr = encodeBuffer.getMsgPtr();
        len = encodeBuffer.getMsgLen();

        const int MAXREADLEN = 1024;
        static char printBuffer[MAXREADLEN];
        memset(printBuffer, 0, MAXREADLEN);
        OpPOIInfoPush_NotificationPDU.toString(printBuffer, MAXREADLEN);

        printf("send %s\n", printBuffer);

        packet =
            build_ipcp_packet(service_id, oper_id, oper_type, payload_type, (char*)msgptr, len);
        error_code = ipcp_send(udp_peer, packet);
    }

    sleep(2);

    ipcp_cleanup();

    return 0;
}